/*******************************************************************************
 * Copyright (c) 2003 Boris Pruessmann and others. All rights reserved. This
 * program and the accompanying materials are made available under the terms of
 * the Common Public License v0.5 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.action;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.IFileType;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.resources.IP4File;
import net.sourceforge.perforce.ui.dialogs.FileTypeDialog;
import net.sourceforge.perforce.ui.internal.Policy;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.operation.IRunnableWithProgress;

import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class ChangeFileTypeAction extends PerforceAction {
  //----------------------------------------------------------------------------
  // -- Public Methods

  @Override
  public void run(IAction action) {
    final IP4File[] files = SelectionHelper.getSelectedPerforceFiles(getSelection());
    Policy.assertTrue(files.length > 0);

    final FileTypeDialog dialog = new FileTypeDialog(getShell(), files[0].getFileType());
    if (dialog.open() != FileTypeDialog.OK) {
      return;
    }

    run(new IRunnableWithProgress() {
      public void run(IProgressMonitor monitor) throws InvocationTargetException {
        final IFileType newFileType = dialog.getFileType();
        final Map<IPerforceServer, Set<IP4File>> serverMap = getServerMapping(files);

        try {
          monitor.beginTask("", serverMap.size() * 1000); //$NON-NLS-1$
          monitor.setTaskName(Policy.bind("ChangeFileTypeAction.Changing_File_Type")); //$NON-NLS-1$

          int j = 0;
          final IPerforceServer[] servers = new IPerforceServer[serverMap.size()];
          for (Iterator<IPerforceServer> it = serverMap.keySet().iterator(); it.hasNext()
              && !monitor.isCanceled();) {
            IPerforceServer server = it.next();
            servers[j++] = server;

            Set<IP4File> fileSet = serverMap.get(server);

            int i = 0;
            IPath[] filenames = new IPath[fileSet.size()];
            for (IP4File file : fileSet) {
              filenames[i++] = file.getLocation();
            }

            try {
              IProgressMonitor subMonitor =
                  Policy.subMonitorFor(monitor, 1000, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL);
              server.reopen(null, newFileType, filenames, subMonitor);
            } catch (PerforceException e) {
              throw new InvocationTargetException(e);
            }


            PerforceCorePlugin.getPlugin().broadcastChangelistStateChanges(servers);
          }
        } finally {
          monitor.done();
        }

      }
    }, PROGRESS_DIALOG);
  }

  // ---------------------------------------------------------------------------
  // Protected Methods

  @Override
  protected boolean isEnabled() {
    IP4File[] files = SelectionHelper.getSelectedPerforceFiles(getSelection());
    return files.length > 0;
  }

  //----------------------------------------------------------------------------
  // - Private Methods

  /**
   * Returns the server mapping for the given files.
   * 
   * @param files array of files.
   * @return map containing a mapping between servers and sets of files.
   */
  private Map<IPerforceServer, Set<IP4File>> getServerMapping(IP4File[] files) {
    final Map<IPerforceServer, Set<IP4File>> result = Maps.newHashMap();
    for (int i = 0; i < files.length; i++) {
      final IP4File file = files[i];

      Set<IP4File> tempSet = result.get(file.getServer());
      if (tempSet == null) {
        tempSet = Sets.newHashSet();
        result.put(file.getServer(), tempSet);
      }

      tempSet.add(file);
    }

    return result;
  }

}
